home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / hamradio / tnos-2.000 / tnos-2 / trace.c < prev    next >
C/C++ Source or Header  |  1996-07-21  |  15KB  |  603 lines

  1. /* Packet tracing - top level and generic routines, including hex/ascii
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * Mods by G1EMM
  5.  *
  6.  * Tracing to session taken from WNOS3, by Johan. K. Reinalda, WG7J
  7.  */
  8. #include "global.h"
  9. #include "ctype.h"
  10. #include "commands.h"
  11. #include <time.h>
  12. #ifdef ANSIPROTO
  13. #include <stdarg.h>
  14. #endif
  15. #include "mbuf.h"
  16. #include "iface.h"
  17. #include "pktdrvr.h"
  18. #include "session.h"
  19. #include "trace.h"
  20. #include "usock.h"
  21.  
  22. #if !defined(_lint) && !defined(MSDOS)
  23. static char rcsid[] OPTIONAL = "$Id: trace.c,v 1.16 1996/07/21 23:54:49 root Exp root $";
  24. #endif
  25.  
  26. /* this variable and the patch to traceprintf assumes that no pwaits
  27.    will be placed in any of the files used for tracing. */
  28.  
  29. int tracesock;
  30.  
  31.  
  32. #ifdef TRACE
  33. static void ascii_dump __ARGS ((FILE * fp, struct mbuf ** bpp));
  34. static void ctohex __ARGS ((char *buf, int16 c));
  35. static void fmtline __ARGS ((FILE * fp, int16 addr, char *buf, int16 len));
  36. static void hex_dump __ARGS ((FILE * fp, struct mbuf ** bpp, int iftype));
  37. static void showtrace __ARGS ((struct iface * ifp));
  38. static void plain_dump __ARGS ((FILE * fp, register struct mbuf ** bpp));
  39.  
  40. #ifdef MULTITASK
  41. extern int Nokeys;
  42. #endif
  43.  
  44. extern int Tracesession;
  45. extern struct session *Trace;
  46.  
  47. #include "slip.h"
  48.  
  49. #ifdef MONITOR
  50. int Trace_compact_header = 0;
  51. static const char *kissname __ARGS ((struct iface * ifp, struct mbuf * bp, unsigned type));
  52.  
  53.  
  54. static const char *
  55. kissname (struct iface *ifp, struct mbuf *bp, unsigned type)
  56. {
  57. int port;
  58.  
  59.     if (ifp->type != CL_AX25 || type != CL_KISS)
  60.         return ifp->name;
  61.     port = (bp->data[0] & 0xF0) >> 4;
  62.     if (Slip[ifp->xdev].kiss[port] == NULLIF)
  63.         return ifp->name;
  64.     return Slip[ifp->xdev].kiss[port]->name;
  65. }
  66.  
  67. #endif
  68.  
  69.  
  70. int
  71. dostrace (int argc, char *argv[], void *p OPTIONAL)
  72. {
  73.     if (Trace == NULLSESSION) {
  74.         if (argc > 1)
  75.             tputs ("Session tracing not available!\007\n");
  76.         argc = 0;    /* No session setup, so don't allow turning it on ! */
  77.     }
  78.     return setbool (&Tracesession, "Trace to session", argc, argv);
  79. }
  80.  
  81.  
  82. /* Redefined here so that programs calling dump in the library won't pull
  83.  * in the rest of the package
  84.  */
  85.  
  86. static char nospace[] = "No space!!\n";
  87.  
  88. struct tracecmd DFAR Tracecmd[] =
  89. {
  90.     { "input",    IF_TRACE_IN,    IF_TRACE_IN },
  91.     { "-input",    0,        IF_TRACE_IN },
  92.     { "output",    IF_TRACE_OUT,    IF_TRACE_OUT },
  93.     { "-output",    0,        IF_TRACE_OUT },
  94.     { "broadcast",    0,        IF_TRACE_NOBC },
  95.     { "-broadcast",    IF_TRACE_NOBC,    IF_TRACE_NOBC },
  96.     { "raw",    IF_TRACE_RAW,    IF_TRACE_RAW },
  97.     { "-raw",    0,        IF_TRACE_RAW },
  98.     { "ascii",    IF_TRACE_ASCII,    IF_TRACE_ASCII | IF_TRACE_HEX },
  99.     { "-ascii",    0,        IF_TRACE_ASCII | IF_TRACE_HEX },
  100.     { "hex",    IF_TRACE_HEX,    IF_TRACE_ASCII | IF_TRACE_HEX },
  101.     { "-hex",    IF_TRACE_ASCII,    IF_TRACE_ASCII | IF_TRACE_HEX },
  102. #ifdef MONITOR
  103. /* borrow a meaningless combination for the new trace type */
  104. #define IF_TRACE_PLAIN (IF_TRACE_ASCII|IF_TRACE_HEX)
  105.     { "monitor",    IF_TRACE_PLAIN,    IF_TRACE_ASCII | IF_TRACE_HEX },
  106.     { "-monitor",    IF_TRACE_ASCII,    IF_TRACE_ASCII | IF_TRACE_HEX },
  107. #endif
  108.     { "off",    0,        0xffff },
  109.     { NULLCHAR,    0,        0 }
  110. };
  111.  
  112.  
  113.  
  114. void
  115. dump (register struct iface *ifp, int direction, unsigned type, struct mbuf *bp)
  116. {
  117. struct mbuf *tbp;
  118. void (*func) __ARGS ((FILE *, struct mbuf **, int));
  119. int16 size;
  120. time_t timer;
  121. char *cp;
  122.  
  123. #ifdef KISS            /* Let's straighten out this multiport tracing - K5JB */
  124.     if (type == CL_KISS) {    /* I don't think we will see CL_AX25 */
  125.         int port;    /* don't need this but it improves readability */
  126.         struct iface *kifp;
  127.  
  128.         port = (bp->data[0] & 0xF0) >> 4;
  129.         if ((kifp = Slip[ifp->xdev].kiss[port]) != NULLIF)
  130.             ifp = kifp;
  131.     }
  132. #endif
  133.  
  134.     if (ifp == NULL || (ifp->trace & direction) == 0)
  135.         return;        /* Nothing to trace */
  136.  
  137. #ifdef UNIX
  138.     /* need to check if the traced-to session is a "blocking" session */
  139.     if (ifp->trsock != -1 && sm_blocked (Tracesession ? Trace : Command))
  140.         return;
  141. #else
  142.     if (Tracesession) {
  143.         /* Disable trace if this is not Trace-sessions,
  144.              * or when shelled out, and not tracing to file */
  145. #ifdef MULTITASK
  146.         if ((Current != Trace || Nokeys) && (ifp->trfp == stdout))
  147. #else
  148.         if ((Current != Trace) && (ifp->trfp == stdout))
  149. #endif /* MULTITASK */
  150.             return;    /* Nothing to trace */
  151.     } else {
  152.         /* Disable trace on non-command sessions or when shelled out */
  153. #ifdef MULTITASK
  154.         if ((Current != Command || Nokeys) && (ifp->trfp == stdout))
  155. #else
  156.         if ((Current != Command) && (ifp->trfp == stdout))
  157. #endif
  158.             return;    /* Nothing to trace */
  159.     }
  160. #endif
  161.  
  162.     if (ifp->trsock != -1)
  163.         tracesock = ifp->trsock;
  164.     else if (Tracesession)
  165.         tracesock = Trace->output;
  166.     else
  167.         tracesock = Command->output;
  168.  
  169.     (void) time (&timer);
  170.     cp = ctime (&timer);
  171.     cp[24] = '\0';
  172.  
  173.     switch (direction) {
  174.         case IF_TRACE_IN:
  175.             if ((ifp->trace & IF_TRACE_NOBC)
  176.                 && (Tracef[type].addrtest != NULLFP ((struct iface *, struct mbuf *)))
  177.                 && (*Tracef[type].addrtest) (ifp, bp) == 0)
  178.                 return;    /* broadcasts are suppressed */
  179. #ifdef MONITOR
  180.             if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
  181.                 traceprintf (ifp->trfp, "(%s) ", kissname (ifp, bp, type));
  182.             else
  183. #endif
  184.                 traceprintf (ifp->trfp, "\n%s - %s recv:\n", cp, ifp->name);
  185.             break;
  186.         case IF_TRACE_OUT:
  187. #ifdef MONITOR
  188.             if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
  189.                 traceprintf (ifp->trfp, "(%s) ", kissname (ifp, bp, type));
  190.             else
  191. #endif
  192.                 traceprintf (ifp->trfp, "\n%s - %s sent:\n", cp, ifp->name);
  193.             break;
  194.         default:
  195.             break;
  196.     }
  197.     if (bp == NULLBUF || (size = len_p (bp)) == 0) {
  198.         traceprintf (ifp->trfp, "empty packet!!\n");
  199.         return;
  200.     }
  201.     if (type < NCLASS)
  202.         func = Tracef[type].tracef;
  203.     else
  204.         func = NULLVFP ((FILE *, struct mbuf **, int));
  205.  
  206.     (void) dup_p (&tbp, bp, 0, size);
  207.     if (tbp == NULLBUF) {
  208.         traceprintf (ifp->trfp, nospace);
  209.         return;
  210.     }
  211. #ifdef MONITOR
  212.     Trace_compact_header = ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN);
  213. #endif
  214.     if (func != NULLVFP ((FILE *, struct mbuf **, int)))
  215.         (*func) (ifp->trfp, &tbp, 1);
  216. #ifdef MONITOR
  217.     if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
  218.         plain_dump (ifp->trfp, &tbp);
  219.     else
  220. #endif
  221.     if (ifp->trace & IF_TRACE_ASCII) {
  222.         /* Dump only data portion of packet in ascii */
  223.         ascii_dump (ifp->trfp, &tbp);
  224.     } else if (ifp->trace & IF_TRACE_HEX) {
  225.         /* Dump entire packet in hex/ascii */
  226.         free_p (tbp);
  227.         (void) dup_p (&tbp, bp, 0, len_p (bp));
  228.         if (tbp != NULLBUF)
  229.             hex_dump (ifp->trfp, &tbp, ifp->type);
  230.         else
  231.             traceprintf (ifp->trfp, nospace);
  232.     }
  233.     free_p (tbp);
  234. }
  235.  
  236.  
  237. /* Dump packet bytes, no interpretation */
  238. void
  239. raw_dump (struct iface *ifp, int direction, struct mbuf *bp)
  240. {
  241. struct mbuf *tbp;
  242.  
  243.     /* Dump entire packet in hex/ascii */
  244.     traceprintf (ifp->trfp, "\n******* raw packet dump (%s %s)\n",
  245.          ((direction & IF_TRACE_OUT) ? "send" : "recv"), ifp->name);
  246.     (void) dup_p (&tbp, bp, 0, len_p (bp));
  247.     if (tbp != NULLBUF)
  248.         hex_dump (ifp->trfp, &tbp, ifp->type);
  249.     else
  250.         traceprintf (ifp->trfp, nospace);
  251.     traceprintf (ifp->trfp, "*******\n");
  252.     free_p (tbp);
  253.     return;
  254. }
  255.  
  256.  
  257. /* Dump an mbuf in hex */
  258. static void
  259. hex_dump (FILE * fp, register struct mbuf **bpp, int iftype)
  260. {
  261. int16 n;
  262. int16 address;
  263. char buf[16];
  264.  
  265.     if (bpp == NULLBUFP || *bpp == NULLBUF)
  266.         return;
  267.  
  268.     address = 0;
  269.     if (iftype == CL_AX25)
  270.         (void) pullup (bpp, (unsigned char *) buf, 1);    /* remove first zero byte */
  271.     while ((n = pullup (bpp, (unsigned char *) buf, sizeof (buf))) != 0) {
  272.         fmtline (fp, address, buf, n);
  273.         address += n;
  274.     }
  275. }
  276.  
  277.  
  278. /* Dump an mbuf in ascii */
  279. static void
  280. ascii_dump (FILE * fp, register struct mbuf **bpp)
  281. {
  282. int c;
  283. register int16 tot;
  284.  
  285.     if (bpp == NULLBUFP || *bpp == NULLBUF)
  286.         return;
  287.  
  288.     tot = 0;
  289.     while ((c = PULLCHAR (bpp)) != -1) {
  290.         if ((tot % 64) == 0)
  291.             traceprintf (fp, "%04x  ", tot);
  292.         traceprintf (fp, "%c", isprint (uchar (c)) ? c : '.');
  293.         if ((++tot % 64) == 0)
  294.             traceprintf (fp, "\n");
  295.     }
  296.     if ((tot % 64) != 0)
  297.         traceprintf (fp, "\n");
  298. }
  299.  
  300.  
  301. /* Print a buffer up to 16 bytes long in formatted hex with ascii
  302.  * translation, e.g.,
  303.  * 0000: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f  0123456789:;<=>?
  304.  */
  305. static void
  306. fmtline (FILE * fp, int16 addr, char *buf, int16 len)
  307. {
  308. char line[100];
  309. register char *aptr, *cptr;
  310. register char c;
  311.  
  312.     memset (line, ' ', sizeof (line));
  313.     ctohex (line, (int16) hibyte (addr));
  314.     ctohex (line + 2, (int16) lobyte (addr));
  315.     aptr = &line[6];
  316.     cptr = &line[55];
  317.     while (len-- != 0) {
  318.         c = *buf++;
  319.         ctohex (aptr, (int16) uchar (c));
  320.         aptr += 3;
  321.         c &= 0x7f;
  322.         *cptr++ = isprint (uchar (c)) ? c : '.';
  323.     }
  324.     *cptr++ = '\n';
  325.     *cptr = 0;
  326.     traceprintf (fp, "%s", line);
  327. }
  328.  
  329.  
  330. /* Convert byte to two ascii-hex characters */
  331. static void
  332. ctohex (register char *buf, register int16 c)
  333. {
  334. static char hex[] = "0123456789abcdef";
  335.  
  336.     *buf++ = hex[hinibble (c)];
  337.     *buf = hex[lonibble (c)];
  338. }
  339.  
  340.  
  341. #ifdef MONITOR
  342. /* Dump an mbuf in ascii with newlines but no others. */
  343. /* Actually, we do limited VT100 parsing, since that seems popular here */
  344. static void
  345. plain_dump (FILE * fp, register struct mbuf **bpp)
  346. {
  347. struct mbuf *tmp, **tmpp = &tmp;
  348. int c, esc, nl;
  349.  
  350.     if (bpp == NULLBUFP || *bpp == NULLBUF)
  351.         return;
  352.  
  353.     /* check for lots of non-ASCII, non-VT100 and ascii_dump instead? */
  354.     (void) dup_p (&tmp, *bpp, 0, len_p (*bpp));
  355.     nl = 0;
  356.     while ((c = PULLCHAR (tmpp)) != -1) {
  357.         /*
  358.          * Printable characters are okay, as are \n \t \r \b \f \a \E
  359.          * Nulls and other control characters are verboten, as are meta
  360.          * controls.  Meta-printables are accepted, since they may be
  361.          * intended as PC graphics (but don't expect them to dump right
  362.          * from here because I don't decode them.  Maybe someday).
  363.          */
  364.         if (c < 8 || (c > 13 && c < 26) || (c > 27 && c < 32) ||
  365.             (c > 126 && c < 174) || c > 223)
  366.             nl = 1;
  367.     }
  368.     if (nl) {
  369.         ascii_dump (fp, bpp);
  370.         return;
  371.     }
  372.     esc = 0;
  373.     nl = 1;
  374.     while ((c = PULLCHAR (bpp)) != -1) {
  375.         if (c == 0x1B)
  376.             esc = !esc;
  377.         else if (esc == 1 && c == '[')
  378.             esc = 2;
  379.         else if (esc == 1)
  380.             esc = 0;
  381.         else if (esc == 2 && c != ';' && !isdigit (c)) {
  382.             /* handle some common cases? */
  383.             esc = 0;
  384.         } else if (esc == 0 && c == '\r') {
  385.             traceprintf (fp, "\n");
  386.             nl = 1;
  387.         }
  388.         /* safe programming: not everyone *always* agrees on isprint */
  389.         else if (esc == 0 && c != '\n' && (isprint (c) || c == '\t')) {
  390.             traceprintf (fp, "%c", c);
  391.             nl = 0;
  392.         }
  393.     }
  394.     if (!nl)
  395.         traceprintf (fp, "\n");
  396. }
  397.  
  398. #endif
  399.  
  400.  
  401. /* Modify or displace interface trace flags */
  402. int
  403. dotrace (int argc, char *argv[], void *p OPTIONAL)
  404. {
  405. struct iface *ifp;
  406. struct tracecmd *tp;
  407.  
  408.     if (argc < 2) {
  409.         for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next)
  410.             showtrace (ifp);
  411.         return 0;
  412.     }
  413.     if ((ifp = if_lookup (argv[1])) == NULLIF) {
  414.         tprintf (Badinterface, argv[1]);
  415.         return 1;
  416.     }
  417. #if 0
  418.     if (ifp->port) {
  419.         tprintf ("No trace on this interface - use master.\n");
  420.         return 1;
  421.     }
  422. #endif
  423.     if (argc == 2) {
  424.         showtrace (ifp);
  425.         return 0;
  426.     }
  427.     /* MODIFY THIS TO HANDLE MULTIPLE OPTIONS */
  428.     if (argc >= 3) {
  429.         for (tp = Tracecmd; tp->name != NULLCHAR; tp++)
  430.             if (strncmp (tp->name, argv[2], strlen (argv[2])) == 0)
  431.                 break;
  432.         if (tp->name != NULLCHAR)
  433.             ifp->trace = (int16) ((ifp->trace & (~(unsigned)tp->mask)) | (unsigned)tp->val);
  434.         else
  435.             ifp->trace = (int16) htoi (argv[2]);
  436.     }
  437.     /* Always default to stdout unless trace file is given */
  438.     if (ifp->trsock != -1)
  439.         close_s (ifp->trsock);
  440.     ifp->trsock = -1;
  441.     if (ifp->trfp != NULLFILE && ifp->trfp != stdout)    /*lint !e740 */
  442.         fclose (ifp->trfp);
  443.     ifp->trfp = stdout;        /*lint !e740 */
  444.     if (ifp->trfile != NULLCHAR)
  445.         free (ifp->trfile);
  446.     ifp->trfile = NULLCHAR;
  447.  
  448.     if (argc >= 4) {
  449.         if (argv[3][0] == '!') {
  450.             /* trace to the current output socket ! */
  451.             ifp->trsock = Curproc->output;
  452.             /* make sure stopping trace doesn't kill connection */
  453.             (void) usesock (ifp->trsock);
  454.         } else if ((ifp->trfp = fopen (argv[3], APPEND_TEXT)) == NULLFILE) {
  455.             tprintf ("Can't write to %s\n", argv[3]);
  456.             ifp->trfp = stdout;        /*lint !e740 */
  457.         } else {
  458.             ifp->trfile = strdup (argv[3]);
  459.         }
  460.     }
  461.     showtrace (ifp);
  462.     return 0;
  463. }
  464.  
  465.  
  466. /* Display the trace flags for a particular interface */
  467. static void
  468. showtrace (register struct iface *ifp)
  469. {
  470.     if (ifp == NULLIF)
  471.         return;
  472.     tprintf ("%s:", ifp->name);
  473. #if 0
  474.     if (ifp->port) {
  475.         tprintf (" trace on master interface only.\n");
  476.         return;
  477.     }
  478. #endif
  479.     if (ifp->trace & (IF_TRACE_IN | IF_TRACE_OUT | IF_TRACE_RAW)) {
  480.         if (ifp->trace & IF_TRACE_IN)
  481.             tprintf (" input");
  482.         if (ifp->trace & IF_TRACE_OUT)
  483.             tprintf (" output");
  484.  
  485.         if (ifp->trace & IF_TRACE_NOBC)
  486.             tprintf (" - no broadcasts");
  487.  
  488. #ifdef MONITOR
  489.         if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
  490.             tprintf (" (Monitoring)");
  491.         else
  492. #endif
  493.         if (ifp->trace & IF_TRACE_HEX)
  494.             tprintf (" (Hex/ASCII dump)");
  495.         else if (ifp->trace & IF_TRACE_ASCII)
  496.             tprintf (" (ASCII dump)");
  497.         else
  498.             tprintf (" (headers only)");
  499.  
  500.         if (ifp->trace & IF_TRACE_RAW)
  501.             tprintf (" Raw output");
  502.  
  503.         if (ifp->trfile != NULLCHAR)
  504.             tprintf (" trace file: %s", ifp->trfile);
  505.         else if (ifp->trsock >= SOCKBASE)
  506.             tprintf (" tracing to socket");
  507.         tprintf ("\n");
  508.     } else
  509.         tprintf (" tracing off\n");
  510. }
  511.  
  512.  
  513. /* shut down all trace files */
  514. void
  515. shuttrace ()
  516. {
  517. struct iface *ifp;
  518.  
  519.     for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next) {
  520.         if (ifp->trsock != -1)
  521.             close_s (ifp->trsock);
  522.         if (ifp->trfp != NULLFILE && ifp->trfp != stdout)    /*lint !e740 */
  523.             fclose (ifp->trfp);
  524.         if (ifp->trfile != NULLCHAR)
  525.             free (ifp->trfile);
  526.         ifp->trfile = NULLCHAR;
  527.         ifp->trfp = NULLFILE;
  528.         ifp->trsock = -1;
  529.     }
  530. }
  531.  
  532. #endif /*TRACE*/
  533.  
  534.  
  535. #ifdef PPP
  536. /* Log messages of the form
  537.  * Tue Jan 31 00:00:00 1987 44.64.0.7:1003 open FTP
  538.  */
  539. #if defined(ANSIPROTO)
  540. #if defined(SCREENSAVER) && defined(UNIX)
  541. extern int16 intrace;
  542.  
  543. #endif
  544.  
  545. void
  546. trace_log (struct iface *ifp, const char *fmt,...)
  547. {
  548. va_list ap;
  549. char *cp;
  550. long t;
  551.  
  552.     if (ifp->trfp == NULLFILE)
  553.         return;
  554.  
  555.     (void) time (&t);
  556.     cp = ctime (&t);
  557.     rip (cp);
  558.     traceprintf (ifp->trfp, "%s", cp);
  559.  
  560.     traceprintf (ifp->trfp, " - ");
  561.     va_start (ap, fmt);            /*lint !e718 !e746 */
  562. #if defined(SCREENSAVER) && defined(UNIX)
  563.     intrace = 1;
  564. #endif
  565.     if (ifp->trfp == stdout)        /*lint !e740 */
  566.         (void) usvprintf (tracesock, fmt, ap);
  567.     else
  568.         (void) vfprintf (ifp->trfp, fmt, ap);
  569. #if defined(SCREENSAVER) && defined(UNIX)
  570.     intrace = 0;
  571. #endif
  572.     va_end (ap);
  573.     traceprintf (ifp->trfp, "\n");
  574. }
  575.  
  576. #else
  577.  
  578. /* VARARGS2 */
  579. void
  580. trace_log (ifp, fmt, arg1, arg2, arg3, arg4, arg5)
  581. struct iface *ifp;
  582. const char *fmt;
  583. int arg1, arg2, arg3, arg4, arg5;
  584. {
  585. char *cp;
  586. long t;
  587.  
  588.     if (ifp->trfp == NULLFILE)
  589.         return;
  590.  
  591.     time (&t);
  592.     cp = ctime (&t);
  593.     rip (cp);
  594.     traceprintf (ifp->trfp, "%s", cp);
  595.  
  596.     traceprintf (ifp->trfp, " - ");
  597.     traceprintf (ifp->trfp, fmt, arg1, arg2, arg3, arg4, arg5);
  598.     traceprintf (ifp->trfp, "\n");
  599. }
  600.  
  601. #endif
  602. #endif /* PPP */
  603.